package org.example.ims.Service.Order.Impl;

import org.example.ims.DTO.StockInOutDTO;
import org.example.ims.Entity.Order.OutStockDetail;
import org.example.ims.Entity.Order.OutStockOrder;
import org.example.ims.Entity.Base.Product;
import org.example.ims.Entity.Base.Warehouse;
import org.example.ims.Entity.WareHouseProduct.WarehouseProduct;
import org.example.ims.Entity.WareHouseProduct.WarehouseProductId;
import org.example.ims.Repository.Order.OutStockDetailRepository;
import org.example.ims.Repository.Order.OutStockOrderRepository;
import org.example.ims.Repository.Base.ProductRepository;
import org.example.ims.Repository.Base.WarehouseRepository;
import org.example.ims.Repository.WarehouseProduct.WarehouseProductRepository;
import org.example.ims.Service.Order.OutStockDetailService;
import org.example.ims.Utils.Detail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;

@Service("outStockDetailService")
public class OutStockDetailServiceImpl implements OutStockDetailService {
    @Autowired
    private  OutStockDetailRepository detailRepository;
    @Autowired
    private WarehouseProductRepository warehouseProductRepository;
    @Autowired
    private  ProductRepository productRepository;
    @Autowired
    private  WarehouseRepository warehouseRepository;
    @Autowired
    private OutStockOrderRepository outStockOrderRepository;


    @Override
    public OutStockDetail createDetail(OutStockDetail detail) {
        // 验证关联实体是否存在
        validateRelatedEntities(detail);
        return detailRepository.save(detail);
    }

    @Override
    public OutStockDetail updateDetail(Integer detailId, OutStockDetail detail) {
        // 验证详情是否存在
        OutStockDetail existingDetail = detailRepository.findById(detailId)
                .orElseThrow(() -> new NoSuchElementException("OutStockDetail not found with id: " + detailId));

        // 验证关联实体是否存在
        validateRelatedEntities(detail);

        // 更新可编辑字段
        if (detail.getQuantity() != null) {
            existingDetail.setQuantity(detail.getQuantity());
        }
        if (detail.getProductId() != null) {
            existingDetail.setProductId(detail.getProductId());
        }
        if (detail.getOrder() != null) {
            existingDetail.setOrder(detail.getOrder());
        }

        return detailRepository.save(existingDetail);
    }

    @Override
    public void deleteDetail(Integer detailId) {
        if (!detailRepository.existsById(detailId)) {
            throw new NoSuchElementException("OutStockDetail does not exist with id: " + detailId);
        }
        detailRepository.deleteById(detailId);
    }

    @Override
    public OutStockDetail getDetailById(Integer detailId) {
        return detailRepository.findById(detailId)
                .orElseThrow(() -> new NoSuchElementException("OutStockDetail not found with id: " + detailId));
    }

    @Override
    public Page<OutStockDetail> getAllDetails(Integer page, Integer size) {
        return detailRepository.findAll(PageRequest.of(page, size));
    }

    @Override
    public Page<OutStockDetail> searchDetails(Integer orderId, Integer productId, Integer warehouseId, Integer page, Integer size) {
        return detailRepository.findAll(buildSpecification(orderId, productId, warehouseId), PageRequest.of(page, size));
    }

    private Specification<OutStockDetail> buildSpecification(Integer orderId, Integer productId, Integer warehouseId) {
        return (root, query, cb) -> {
            return cb.and(
                    orderId != null ? cb.equal(root.join("order").get("orderId"), orderId) : null,
                    productId != null ? cb.equal(root.join("product").get("productId"), productId) : null,
                    warehouseId != null ? cb.equal(root.join("warehouse").get("warehouseId"), warehouseId) : null
            );
        };
    }

    @Override
    public StockInOutDTO<WarehouseProduct> validityAssessment(List<OutStockDetail> details, Warehouse warehouse) {
        //和入库逻辑不同，这里直接在WP里搜索，没有记录就是没有商品库存，即订单的商品信息异常。
        //虽然放在outStockDetail中但实际就是WP的service
        List<Detail<WarehouseProduct>> info= new ArrayList<>();
        int allNeed =0;
        for (OutStockDetail detail : details) {
            WarehouseProductId warehouseProductId = new WarehouseProductId(warehouse.getWarehouseId(), detail.getProductId());

            //对于null就是这个仓库没有这个商品
            WarehouseProduct warehouseProduct = warehouseProductRepository.findById(warehouseProductId)
                    .orElseThrow(() -> new RuntimeException("Product " + warehouseProductId.getWarehouseId() +
                            "not found in " + warehouseProductId.getWarehouseId()));

            //判断此商品是否数量充足
            if (warehouseProduct.getQuantity() < detail.getQuantity()) {
                throw new RuntimeException("Insufficient stock for product " + warehouseProductId.getProductId());
            }
            //计算对应的容量
            Product product = warehouseProduct.getProduct();
            //累加
            allNeed += detail.getQuantity();
            //将WP插入
            Detail<WarehouseProduct> key = new Detail<>(warehouseProduct,detail.getQuantity());
            info.add(key);
        }
        return new StockInOutDTO<>(info, allNeed);
    }

    private void validateRelatedEntities(OutStockDetail detail) {
        if (detail.getOrder() != null && detail.getOrder().getOrderId() != null) {
            Optional<OutStockOrder> order = outStockOrderRepository.findById(detail.getOrder().getOrderId());
            if (!order.isPresent()) {
                throw new NoSuchElementException("OutStockOrder not found with id: " + detail.getOrder().getOrderId());
            }
        }

        if (detail.getProductId() != null) {
            Optional<Product> product = productRepository.findById(detail.getProductId());
            if (!product.isPresent()) {
                throw new NoSuchElementException("Product not found with id: " + detail.getProductId());
            }
        }
    }
}